Items in a listbox can be selected both through end-user interactions and programmatically. The SelectionMode property defines how the items in a listbox can be selected through end-user interactions. SelectionMode.Single (default) indicates that only one item can be selected at a time. Multiple indicates that multiple items can be selected without pressing the CTRL or SHIFT modifier keys. Extended indicates that multiple items can be selected by pressing a modifier key.
Retrieving the Selected Items
By using the BeginGetSelectedItems and EndGetSelectedItems asynchronous methods, the items that are currently selected in a listbox can be retrieved. When dealing with a local data source (i.e., "full list"), the BeginGetSelectedItems method will return immediately and the value of the IsCompleted property of the returned IAsyncResult will be true, indicating that the operation has been completed. The EndGetSelectedItems method can then be called to finalize the process and get the selected items. If a virtualized data source is used, the EndGetSelectedItems method needs to be called in the callback after verifying whether the operation completed synchronously or not.
Private Sub GetSelectedItems()
Dim result As IAsyncResult = Me.listBox.BeginGetSelectedItems( New AsyncCallback( AddressOf Me.ProcessSelectedItems ), Nothing )
If( result.IsCompleted ) Then
Dim selectedItems As IEnumerable( Of Object ) = Me.listBox.EndGetSelectedItems( result )
End If
End Sub
Private Sub ProcessSelectedItems( ByVal result As IAsyncResult )
If( result.CompletedSynchronously ) Then
Return
End If
Dim selectedItems As IEnumerable( Of Object ) = Me.listBox.EndGetSelectedItems( result )
End Sub
private void GetSelectedItems()
{
IAsyncResult result = this.listBox.BeginGetSelectedItems( new AsyncCallback( this.ProcessSelectedItems ), null );
if( result.IsCompleted )
IEnumerable<object> selectedItems = this.listBox.EndGetSelectedItems( result );
}
private void ProcessSelectedItems( IAsyncResult result )
{
if( result.CompletedSynchronously )
return;
IEnumerable<object> selectedItems = this.listBox.EndGetSelectedItems( result );
}
The SelectedItems, SelectedItem, SelectedValue, and SelectedValuePath properties should only be used with sources that are not data-virtualized (asynchronous): the BeginGetSelectedItems and EndGetSelectedItems methods should be used instead if the data source is data-virtualized (asynchronous). If used with an asynchronous source, SelectedItems will throw an exception, SelectedItem and SelectedValue will always return null, and SelectedValuePath will have no effect.
Selecting Items Programmatically
Items can be selected by adding selection ranges to a listbox's SelectedRanges property. Each range that is added to the collection represents a group of items that have matched one or more selection criteria. Programmatically, a selection range can only be created if the data it is working with is sorted. In order to sort the data, one or more SortDescription objects, which will be used to create the data query that is sent to the data source, must be provided at construction time.
A selection range defines "start" and "end" range-information dictionaries that specify the start and end points of a range of selected items (see StartRangeInfos and EndRangeInfos properties). For each start/end range-information dictionary combination that is added to the selection range, a corresponding sort description, whose PropertyName property value matches the key of the start/end range-information dictionary combination, must also be provided (see examples below).
The sort descriptions used by a selection range have no impact on how the data is actually sorted in the listbox and vice-versa.
In addition, both the start/end range-information dictionaries (i.e., StartRangeInfos and EndRangeInfos, respectively) expose an IsInclusive property that determines whether the start or end range-information dictionaries are inclusive, indicating that their values are included in the selection range (default), or if they are excluded from the selection range. These properties apply to all the range-information dictionary combinations specified in the StartRangeInfos and EndRangeInfos dictionaries.
Predicates (i.e., filter parameter in the SelectionRange ctors) are executed locally meaning that when the BeginGetSelectedItems and EndGetSelectedItems are called and a selection range that provides a predicate is used, items will be retrieved from the server in order to determine those that pass the filter.
If one or more start and end range information dictionary is provided and/or a filter expression, only the items that are not already excluded by the range information and filter expression will be retrieved.
In a virtualized environment, it is not recommended to use the filter predicate unless dealing with a very limited number of items.
Items can also be unselected by creating a selection range and setting its SelectionType property to Unselect (see Unselecting items from a selection range example below).
The following examples cover most, if not all, possible scenarios.
Selecting all items
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( SelectionRange.All )
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( SelectionRange.All );
Selecting specific items (ShipCountry = "Germany")
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing)
range.StartRangeInfos.Add( "ShipCountry", "Germany" )
range.EndRangeInfos.Add( "ShipCountry", "Germany" )
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
range.StartRangeInfos.Add( "ShipCountry", "Germany" );
range.EndRangeInfos.Add( "ShipCountry", "Germany" );
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Selecting items within a range (ShipCountry = "A-M")
Dim range As New SelectionRange( New SortDescription() { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
range.StartRangeInfos.Add( "ShipCountry", "A" )
range.EndRangeInfos.Add( "ShipCountry", "N" )
range.EndRangeInfos.IsInclusive = False
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
range.StartRangeInfos.Add( "ShipCountry", "A" );
range.EndRangeInfos.Add( "ShipCountry", "N" );
range.EndRangeInfos.IsInclusive = false;
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Selecting items using a filter expression (ShipVia !=3)
Dim expression As New FilterExpression( "ShipVia", FilterOperator.NotEqual, 3 )
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "OrderDate", ListSortDirection.Ascending ) }, expression, Nothing )
range.StartRangeInfos.Add( "OrderDate", New DateTime( 2006, 01, 01 ) )
range.EndRangeInfos.Add( "OrderDate", New DateTime( 2006, 12, 31 ) )
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
FilterExpression expression = new FilterExpression( "ShipVia", FilterOperator.NotEqual, 3 );
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "OrderDate", ListSortDirection.Ascending ) }, expression, null );
range.StartRangeInfos.Add( "OrderDate", new DateTime( 2006, 01, 01 ) );
range.EndRangeInfos.Add( "OrderDate", new DateTime( 2006, 12, 31 ) );
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Selecting items using combined filter expressions (ShipVia = 3 OR OrderDate >= 2008/01/01)
Dim leftExpression As New FilterExpression( "ShipVia", FilterOperator.Equal, 3 )
Dim rightExpression As New FilterExpression( "OrderDate", FilterOperator.GreaterThanOrEqual, New DateTime( 2008, 01, 01 ) )
Dim expression As New OrFilterExpression( leftExpression, rightExpression )
Dim range As New SelectionRange( expression, Nothing )
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
FilterExpression leftExpression = new FilterExpression( "ShipVia", FilterOperator.Equal, 3 );
FilterExpression rightExpression = new FilterExpression( "OrderDate", FilterOperator.GreaterThanOrEqual, new DateTime( 2008, 01, 01 ) );
OrFilterExpression expression = new OrFilterExpression( leftExpression, rightExpression );
SelectionRange range = new SelectionRange( expression, null );
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Selecting items using multiple selection-range infos (ShipVia = 2 AND OrderDate = 2006)
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipVia", ListSortDirection.Ascending ),
New SortDescription( "OrderDate", ListSortDirection.Ascending )}, Nothing, Nothing )
range.StartRangeInfos.Add( "ShipVia", 2 )
range.StartRangeInfos.Add( "OrderDate", New DateTime( 2006, 01, 01 ) )
range.EndRangeInfos.Add( "ShipVia", 2 )
range.EndRangeInfos.Add( "OrderDate", New DateTime( 2006, 12, 31 ) )
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipVia", ListSortDirection.Ascending ),
new SortDescription( "OrderDate", ListSortDirection.Ascending )}, null, null );
range.StartRangeInfos.Add( "ShipVia", 2 );
range.StartRangeInfos.Add( "OrderDate", new DateTime( 2006, 01, 01 ) );
range.EndRangeInfos.Add( "ShipVia", 2 );
range.EndRangeInfos.Add( "OrderDate", new DateTime( 2006, 12, 31 ) );
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Selecting items using a predicate delegate (ShippedDate > RequiredDate)
Dim range As New SelectionRange( Nothing, New Predicate(Of Object)( IsPastRequiredDate ) )
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
Private Function IsPastRequiredDate( ByVal value As Object ) As Boolean
Dim order As Order = CType( value, Order )
If order Is Nothing Then
return False
End If
Return ( order.ShippedDate > order.RequiredDate )
End Function
SelectionRange range = new SelectionRange( null, new Predicate<object>( IsPastRequiredDate ) );
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
private bool IsPastRequiredDate( object value )
{
Order order = value as Order;
if( order == null )
return false;
return ( order.ShippedDate > order.RequiredDate );
}
Selecting items using multiple selection ranges (ShipCountry = "A-D" AND ShipCountry = "M-S")
Dim firstRange As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
Dim secondRange As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
firstRange.StartRangeInfos.Add( "ShipCountry", "A" )
firstRange.EndRangeInfos.Add( "ShipCountry", "D" )
secondRange.StartRangeInfos.Add( "ShipCountry", "M" )
secondRange.EndRangeInfos.Add( "ShipCountry", "S" )
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( firstRange )
Me.listBox.SelectedRanges.Add( secondRange )
SelectionRange firstRange = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
SelectionRange secondRange = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
firstRange.StartRangeInfos.Add( "ShipCountry", "A" );
firstRange.EndRangeInfos.Add( "ShipCountry", "D" );
secondRange.StartRangeInfos.Add( "ShipCountry", "M" );
secondRange.EndRangeInfos.Add( "ShipCountry", "S" );
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( firstRange );
this.listBox.SelectedRanges.Add( secondRange );
Selecting items from start to specified end point
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
' Select all items from the start to "C". All items that start with "A" or "B" will be selected.
' Using "B" only would not work since, for example, "Belgium" "B".
range.StartRangeInfos.FromStart()
range.EndRangeInfos.Add( "ShipCountry", "C" )
range.EndRangeInfos.IsInclusive = False
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
// Select all items from the start to "C". All items that start with "A" or "B" will be selected.
// Using "B" only would not work since, for example, "Belgium" "B".
range.StartRangeInfos.FromStart();
range.EndRangeInfos.Add( "ShipCountry", "C" );
range.EndRangeInfos.IsInclusive = false;
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Selecting items from specified start point to end
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
range.StartRangeInfos.Add( "ShipCountry", "B" )
range.EndRangeInfos.ToEnd()
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
range.StartRangeInfos.Add( "ShipCountry", "B" );
range.EndRangeInfos.ToEnd();
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
Unselecting items from a selection range
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
range.SelectionType = SelectionType.Unselection
range.StartRangeInfos.Add( "ShipCountry", "Canada" )
range.EndRangeInfos.Add( "ShipCountry", "Canada" )
listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
range.SelectionType = SelectionType.Unselection;
range.StartRangeInfos.Add( "ShipCountry", "Canada" );
range.EndRangeInfos.Add( "ShipCountry", "Canada" );
listBox.SelectedRanges.Add( range );
Selecting from and to a specific item (LOCAL LIST ONLY)
Dim range As New SelectionRange()
range.StartRangeInfos.FromItem( Me.People[ 5 ] )
range.EndRangeInfos.ToItem( Me.People[ 10 ] )
listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange();
range.StartRangeInfos.FromItem( this.People[ 5 ] );
range.EndRangeInfos.ToItem( this.People[ 10 ] );
listBox.SelectedRanges.Add( range );
Selecting a single item from a remote data source (WCF DataServiceQuery)
Public Sub GetOrder( ByVal orderID As Integer )
Dim query As DataServiceQuery( Of Order )= TryCast( Data.Orders.Where( order => order.OrderID = orderID ), DataServiceQuery( Of Order ) )
If Not query Is Nothing Then
Dim result As IAsyncCallback= query.BeginExecute( New AsyncCallback( AddressOf Me.ProcessItem ), query )
End If
End Sub
Private Sub ProcessItem( Dim result As IAsyncResult )
Dim query As DataServiceQuery( Of Order )= TryCast( result.AsyncState, DataServiceQuery( Of Order )
If Not query Is Nothing Then
Dim q As IEnumerable( Of Order ) = query.EndExecute( result )
Dim order As Order = q.FirstOrDefault()
Dim range = New SelectionRange( order )
listBox.SelectedRanges.Clear()
listBox.SelectedRanges.Add( range )
End If
End Sub
Private Sub Button_Click( ByVal sender As Object, ByVal e As RoutedEventArgs )
Dim orderIDString As String = orderIDTextBox.Text.Trim()
If Not string.IsNullOrWhiteSpace( orderIDString ) Then
Me.GetOrder( System.Convert.ToInt32( orderIDString ) )
End If
End Sub
public void GetOrder( int orderID )
{
DataServiceQuery<Order> query = Data.Orders.Where( order => order.OrderID == orderID ) as DataServiceQuery<Order>;
if( query != null )
IAsyncResult result = query.BeginExecute( new AsyncCallback( this.ProcessItem ), query );
}
private void ProcessItem( IAsyncResult result )
{
DataServiceQuery<Order> query = result.AsyncState as DataServiceQuery<Order>;
if( query != null )
{
IEnumerable<Order> q = query.EndExecute( result );
Order order = q.FirstOrDefault();
SelectionRange range = new SelectionRange( order );
listBox.SelectedRanges.Clear();
listBox.SelectedRanges.Add( range );
}
}
private void Button_Click( object sender, RoutedEventArgs e )
{
string orderIDString = orderIDTextBox.Text.Trim();
if( !string.IsNullOrWhiteSpace( orderIDString ) )
this.GetOrder( System.Convert.ToInt32( orderIDString ) );
}
Selection-Changed Notifications
Selection-changed notifications are provided via the SelectionChanged event, which is raised whenever the selection in a listbox changes, whether by end-user interaction or through programmatic modifications of the selected ranges.